package java44th.group.config;

import java44th.group.config.realm.CustomRealm;
import java44th.group.config.realm.ShiroUserFilter;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.security.auth.Subject;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @ProjectName project-second
 * @Descriptiom TODO
 * @Aurhor: 蔡文强
 * @Since: 2022/10/14 10:26
 */
@Configuration
public class ShiroConfiguration {

    /*ShiroFilter 需要 SecurityManager 这个核心的组件*/

    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 提供Filter链 -> 配置的内容类似之前的HandlerInterceptor
        // 1.Filter是谁 → anon、authc、perms
        // 2.Filter的作用范围是什么 → 建立请求URL和Filter之间的映射关系
        // 3.Filter之间的顺序 → 书写顺序

        Map<String, Filter> filters = new HashMap<>();
        filters.put("authc", new ShiroUserFilter());
        shiroFilterFactoryBean.setFilters(filters);

        // 必须按照 anon ← authc ← perms 从左到右的顺序去写filter


        // 根据2和3 映射关系与有序 这里使用的是LinkedHashMap
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 开始配置键值对
        // map 中 key   → 请求url
        // map 中 value → filter名称

        filterChainDefinitionMap.put("/admin/auth/login", "anon");
        filterChainDefinitionMap.put("/admin/auth/info", "anon");
        filterChainDefinitionMap.put("/admin/auth/logout", "anon");
        filterChainDefinitionMap.put("/admin/auth/noAuthc", "anon");
        filterChainDefinitionMap.put("/admin/**", "authc");

        filterChainDefinitionMap.put("/wx/brand/detail", "anon");
        filterChainDefinitionMap.put("/wx/cart/goodscount", "anon");
        filterChainDefinitionMap.put("/wx/auth/login", "anon");
        filterChainDefinitionMap.put("/wx/catalog/index", "anon");
        filterChainDefinitionMap.put("/wx/home/index", "anon");
        filterChainDefinitionMap.put("/wx/auth/**", "anon");
        filterChainDefinitionMap.put("/wx/search/**", "anon");
        filterChainDefinitionMap.put("/wx/goods/count", "anon");


        filterChainDefinitionMap.put("/wx/brand/**", "anon");
        filterChainDefinitionMap.put("/wx/topic/**", "anon");
        filterChainDefinitionMap.put("/wx/comment/**", "anon");

        filterChainDefinitionMap.put("/wx/catalog/current", "anon");
        filterChainDefinitionMap.put("/wx/catalog/index", "anon");
        filterChainDefinitionMap.put("/wx/search/index", "anon");
        filterChainDefinitionMap.put("/wx/search/helper", "anon");
        filterChainDefinitionMap.put("/wx/storage/upload", "anon");

        filterChainDefinitionMap.put("/wx/goods/detail", "anon");
        filterChainDefinitionMap.put("/wx/goods/related", "anon");
        filterChainDefinitionMap.put("/wx/goods/category", "anon");
        filterChainDefinitionMap.put("/wx/goods/list", "anon");

        filterChainDefinitionMap.put("/wx/**", "authc");

        // 含义就是访问/admin/user/List这个请求需要的权限就是aaa
        // 但是通常不会这样写，因为增加权限通常指的是url→对handler方法做访问控制
        // filterChainDefinitionMap.put("/admin/user/list","perms[aaa]");
        // 我们会通过耦合的方式做这件事
        // 耦合  使用handler方法和权限做耦合 （使用一点AspectJ的内容）
        // AspectJ的内容
        // 1.导包AspectJweaver
        // 2.在这个类里面配置AuthorizationAttributeSourceAdviser组件
        // 3.在设置权限的URI上增加注解@RequiresPermisson（权限名，如"aaa"）


        // 如果访问某个请求的时候，该请求对应的filter是authc，如果没有通过这个Filter说明没有权限
        // shiro会做一个重定向 → 默认的重定向的地址 /login.jsp
        // 历史遗留问题，想改得自己重新设置重定向的地址
        // 注意 该URL也需要设置为anon
        //  shiroFilterFactoryBean.setLoginUrl("/admin/auth/noAuthc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /*SecurityManager 核心组件：
     * Authenticator  可有可无
     * Authorizaer 可有可无
     * 以上两个是因为SecurityManager提供的默认的这两个组件功能就已经很丰富了
     * 以下两个需要自己配置
     * Realms
     * SessionManager
     * */

    @Bean
    public DefaultWebSecurityManager shiroFilterFactoryBean(AuthorizingRealm realm,
                                                            DefaultWebSessionManager sessionManager) {

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 给SecurityManager 默认的认证器和授权器都设置了Realms
        securityManager.setRealms(Arrays.asList(realm));
        securityManager.setSessionManager(sessionManager);


        return securityManager;
    }

    /*
     * Realm 需要继承AuthorizingRealm
     * 直接增加@Component注册为容器中的组件（在realm包下）
     * */


    /*
     * SessionManager
     * 注意是shiro提供的包
     * */

    @Bean
    public DefaultWebSessionManager sessionManager() {
        // return new DefaultWebSessionManager();
        return new MarketSessionManager();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
        // 这个组件需要传入  securityManager组件  ，然后其他的事情(切入点和通知)该组件会帮我们完成
        // 在执行对应的通知方法时候需要用到 securityManager ，所以这里要传入这个组件
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

}
